home *** CD-ROM | disk | FTP | other *** search
/ Scene Storm / Scene Storm - Volume 1.iso / coding / c / unix / src / pipe.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-08-24  |  8.5 KB  |  340 lines

  1. #include "amiga.h"
  2. #include "files.h"
  3. #include "fifofd.h"
  4. #include "signals.h"
  5. #include <sys/filio.h>
  6. #include <fcntl.h>
  7. #include <signal.h>
  8. #include <string.h>
  9. #include <stdio.h>
  10. #include <exec/memory.h>
  11. #include <amiga/ioctl.h>
  12.  
  13. /* The pipe system call, using fifo: */
  14.  
  15. static struct MsgPort *create_fifo_port(void)
  16. {
  17.   struct MsgPort *port = AllocMem(sizeof(*port), MEMF_CLEAR | MEMF_PUBLIC);
  18.  
  19.   if (!port) return 0;
  20.   port->mp_Node.ln_Type = NT_MSGPORT;
  21.   port->mp_Flags = PA_SIGNAL;
  22.   port->mp_SigBit = _fifo_sig;
  23.   port->mp_SigTask = _us;
  24.   NewList(&port->mp_MsgList);
  25.  
  26.   return port;
  27. }
  28.  
  29. static void delete_fifo_port(struct MsgPort *port)
  30. {
  31.   FreeMem(port, sizeof(*port));
  32. }
  33.  
  34. static void free_fifo(struct fifoinfo *fi)
  35. {
  36.   if (fi->rfifo) CloseFifo(fi->rfifo, 0);
  37.   if (fi->wfifo) CloseFifo(fi->wfifo, FIFOF_EOF);
  38.   if (fi->rmsg) free(fi->rmsg);
  39.   if (fi->wmsg) free(fi->wmsg);
  40.   delete_fifo_port(fi->reply);
  41.   free(fi);
  42. }
  43.  
  44. /* Code for fd's describing fifos */
  45.  
  46. static ULONG fifo_select_start(void *userinfo, int rd, int wr)
  47. {
  48.   struct fifoinfo *fi = userinfo;
  49.  
  50.   if (rd) RequestFifo(fi->rfifo, fi->rmsg, FREQ_RPEND);
  51.   if (wr) RequestFifo(fi->wfifo, fi->wmsg, FREQ_WAVAIL);
  52.   return 1UL << _fifo_sig;
  53. }
  54.  
  55. static void fifo_select_poll(void *userinfo, int *rd, int *wr)
  56. {
  57.   struct fifoinfo *fi = userinfo;
  58.   int rabort = *rd, wabort = *wr;
  59.   struct Message *msg;
  60.  
  61.   while (msg = GetMsg(fi->reply)) 
  62.     {
  63.       if (msg == fi->rmsg) rabort = 0;
  64.       else if (msg == fi->wmsg) wabort = 0;
  65.     }
  66.   if (rabort)
  67.     {
  68.       *rd = 0;
  69.       RequestFifo(fi->rfifo, fi->rmsg, FREQ_ABORT);
  70.     }
  71.   if (wabort)
  72.     {
  73.       *wr = 0;
  74.       RequestFifo(fi->wfifo, fi->wmsg, FREQ_ABORT);
  75.     }
  76.   while (rabort || wabort)
  77.     {
  78.       while (!(msg = GetMsg(fi->reply))) Wait(1UL << _fifo_sig);
  79.       if (msg == fi->rmsg) rabort = 0;
  80.       else if (msg == fi->wmsg) wabort = 0;
  81.     }
  82.   /* Clear any signals we may have left behind */
  83.   SetSignal(0, 1UL << _fifo_sig);
  84. }
  85.  
  86. /* Using 4.2BSD style semantics, with reads from fifo's returning immediately when
  87.    data is available, and blocking for empty fifo's only when O_NDELAY was not
  88.    specified on open */
  89.  
  90. static int fifo_read(void *userinfo, void *buffer, unsigned int length)
  91. {
  92.   struct fifoinfo *fi = userinfo;
  93.   char *chars;
  94.   long ready;
  95.  
  96.   while (!(ready = ReadFifo(fi->rfifo, &chars, fi->skip)))
  97.     {
  98.       ULONG sigs;
  99.  
  100.       fi->skip = 0;
  101.       if (fi->flags & O_NDELAY)
  102.     {
  103.       errno = EWOULDBLOCK;
  104.       return -1;
  105.     }
  106.       Delay(1);            /* Perversely, this improves the performance */
  107.       RequestFifo(fi->rfifo, fi->rmsg, FREQ_RPEND);
  108.       sigs = _wait_signals(1L << fi->reply->mp_SigBit);
  109.       RequestFifo(fi->rfifo, fi->rmsg, FREQ_ABORT);
  110.       while (!GetMsg(fi->reply)) Wait(1UL << _fifo_sig);
  111.  
  112.       _handle_signals(sigs);
  113.     }
  114.   if (ready == -1) ready = 0;
  115.   if (ready > length) ready = length;
  116.   memcpy(buffer, chars, ready);
  117.   fi->skip = ready;
  118.  
  119.   return (int)ready;
  120. }
  121.  
  122. static int fifo_write(void *userinfo, void *buffer, unsigned int length)
  123. {
  124.   struct fifoinfo *fi = userinfo;
  125.   long cansend, written;
  126.  
  127.   if (length == 0)        /* Send EOF */
  128.     {
  129.       char *fname, sname[FIFO_NAMELEN + 2], mname[FIFO_NAMELEN + 2];
  130.  
  131.       /* Send EOF */
  132.       CloseFifo(fi->wfifo, FIFOF_EOF);
  133.       /* And reopen fifo */
  134.       /* Docs say that this clears EOF flag, maybe we should wait a bit ? */
  135.       /* The writer is the "master" in fifo: terms */
  136.       strcpy(mname, fi->name); strcat(mname, "_m");
  137.       strcpy(sname, fi->name); strcat(sname, "_s");
  138.  
  139.       fname = !(fi->flags & FI_READ) || (fi->flags & FIFO_MASTER) ? mname : sname;
  140.       fi->wfifo = OpenFifo(fname, FIFO_BUFSIZE, FIFOF_NORMAL | FIFOF_NBIO |
  141.                FIFOF_WRITE | FIFOF_RREQUIRED);
  142.       if (fi->wfifo)
  143.     {
  144.       fi->maxsend = BufSizeFifo(fi->wfifo) / 2;
  145.       return 0;
  146.     }
  147.       /* We're in trouble. From now on, all writes will fail */
  148.     }
  149.   else if (fi->wfifo)
  150.     {
  151.       cansend = fi->maxsend;
  152.       if (cansend > length) cansend = length;
  153.       while ((written = WriteFifo(fi->wfifo, buffer, cansend)) == 0)
  154.     {
  155.       ULONG sigs;
  156.  
  157.       if (fi->flags & O_NDELAY)
  158.         {
  159.           errno = EWOULDBLOCK;
  160.           return -1;
  161.         }
  162.       RequestFifo(fi->wfifo, fi->wmsg, FREQ_WAVAIL);
  163.       sigs = _wait_signals(1L << fi->reply->mp_SigBit);
  164.       RequestFifo(fi->wfifo, fi->wmsg, FREQ_ABORT);
  165.       while (!GetMsg(fi->reply)) Wait(1UL << _fifo_sig);
  166.       _handle_signals(sigs);
  167.     }
  168.       if (written >= 0) return (int)written;
  169.     }
  170.   /* Some problem has occured */
  171.   _sig_dispatch(SIGPIPE);
  172.   errno = EPIPE;
  173.   return -1;
  174. }
  175.  
  176. static int fifo_lseek(void *userinfo, long rpos, int mode)
  177. {
  178.   errno = ESPIPE;
  179.   return -1;
  180. }
  181.  
  182. static int fifo_close(void *userinfo, int internal)
  183. {
  184.   struct fifoinfo *fi = userinfo;
  185.  
  186.   free_fifo(fi);
  187.   return 0;
  188. }
  189.  
  190. static int fifo_ioctl(void *userinfo, int request, void *data)
  191. {
  192.   struct fifoinfo *fi = userinfo;
  193.  
  194.   switch (request)
  195.     {
  196.     case FIONBIO:
  197.       if (*(int *)data) fi->flags |= O_NDELAY;
  198.       else fi->flags &= ~O_NDELAY;
  199.       return 0;
  200.     case _AMIGA_GET_FH: {
  201.       BPTR *fh = data;
  202.       char name[FIFO_NAMELEN + 12];
  203.  
  204.       /* Get an AmigaDOS fifo: onto the same fifo in the same role */
  205.       if ((fi->flags & (FI_READ | FI_WRITE)) == (FI_READ | FI_WRITE))
  206.     _sprintf(name, "fifo:%s/rwesK%s",
  207.          fi->name, fi->flags & FIFO_MASTER ? "m" : "");
  208.       else if (fi->flags & FI_READ) _sprintf(name, "fifo:%s/r", fi->name);
  209.       else _sprintf(name, "fifo:%s/mweK", fi->name);
  210.       *fh = Open(name, MODE_OLDFILE);
  211.  
  212.       if (*fh) return 0;
  213.       ERROR;
  214.     }
  215.     case _AMIGA_FREE_FH: {
  216.       BPTR *fh = data;
  217.  
  218.       if (*fh) Close(*fh);
  219.       return 0;
  220.     }
  221.     default: errno = EINVAL; return -1;
  222.     }
  223. }
  224.  
  225. static int alloc_fifo(char *name, int reader, int writer, int master)
  226. {
  227.   struct fifoinfo *fi;
  228.   int fd;
  229.   struct MsgPort *reply = 0;
  230.   struct Message *rmsg = 0, *wmsg = 0;
  231.  
  232.   if ((fi = (struct fifoinfo *)malloc(sizeof(struct fifoinfo))) &&
  233.       (reply = create_fifo_port()) &&
  234.       (rmsg = (struct Message *)malloc(sizeof(struct Message))) &&
  235.       (wmsg = (struct Message *)malloc(sizeof(struct Message))))
  236.     {
  237.       rmsg->mn_Node.ln_Type = NT_MESSAGE;
  238.       rmsg->mn_ReplyPort = reply;
  239.       rmsg->mn_Length = sizeof(*rmsg);
  240.       wmsg->mn_Node.ln_Type = NT_MESSAGE;
  241.       wmsg->mn_ReplyPort = reply;
  242.       wmsg->mn_Length = sizeof(*wmsg);
  243.       fi->reply = reply;
  244.       fi->rmsg = rmsg;
  245.       fi->wmsg = wmsg;
  246.       fi->rfifo = fi->wfifo = 0;
  247.  
  248.       fi->flags = 0;
  249.       if (reader) fi->flags |= FI_READ;
  250.       if (writer) fi->flags |= FI_WRITE;
  251.       fd = _alloc_fd(fi, fi->flags, fifo_select_start, fifo_select_poll, fifo_read,
  252.              fifo_write, fifo_lseek, fifo_close, fifo_ioctl);
  253.       if (fd)
  254.     {
  255.       char *fname, sname[FIFO_NAMELEN + 2], mname[FIFO_NAMELEN + 2];
  256.  
  257.       if (master) fi->flags |= FIFO_MASTER;
  258.       strcpy(fi->name, name);
  259.       /* The writer is the "master" in fifo: terms */
  260.       strcpy(mname, fi->name); strcat(mname, "_m");
  261.       strcpy(sname, fi->name); strcat(sname, "_s");
  262.  
  263.       if (reader)
  264.         {
  265.           fname = !writer || !master ? mname : sname;
  266.           fi->rfifo = OpenFifo(fname, FIFO_BUFSIZE, FIFOF_NORMAL | FIFOF_NBIO |
  267.                    FIFOF_READ);
  268.         }
  269.       if (writer)
  270.         {
  271.           fname = !reader || master ? mname : sname;
  272.           fi->wfifo = OpenFifo(fname, FIFO_BUFSIZE, FIFOF_NORMAL | FIFOF_NBIO |
  273.                    FIFOF_WRITE | FIFOF_RREQUIRED);
  274.         }
  275.       if ((fi->rfifo || !reader) && (fi->wfifo || !writer))
  276.         {
  277.           if (fi->wfifo) fi->maxsend = BufSizeFifo(fi->wfifo) / 2;
  278.           fi->skip = 0;
  279.           return fd;
  280.         }
  281.       if (fi->rfifo) CloseFifo(fi->rfifo, 0);
  282.       if (fi->wfifo) CloseFifo(fi->wfifo, 0);
  283.     }
  284.       if (fd >= 0) _free_fd(fd);
  285.     }
  286.   if (rmsg) free(rmsg);
  287.   if (wmsg) free(wmsg);
  288.   if (reply) delete_fifo_port(reply);
  289.   if (fi) free(fi);
  290.   return -1;
  291. }
  292.  
  293. int pipe(int fd[2])
  294. {
  295.   char name[FIFO_NAMELEN];
  296.   struct fileinfo *f0;
  297.  
  298.   chkabort();
  299.   if (!_fifo_ok)
  300.     {
  301.       errno = ENXIO;
  302.       return -1;
  303.     }
  304.  
  305.   _sprintf(name, "uxfifo.%lx", _fifo_base + _fifo_offset++);
  306.  
  307.   if ((fd[0] = alloc_fifo(name, TRUE, FALSE, FALSE)) >= 0)
  308.     if ((fd[1] = alloc_fifo(name, FALSE, TRUE, FALSE)) >= 0) return 0;
  309.     else
  310.       {
  311.     if (f0 = _find_fd(fd[0])) free_fifo(f0->userinfo);
  312.     _free_fd(fd[0]);
  313.       }
  314.   return -1;
  315. }
  316.  
  317. int socketpair(int domain, int type, int protocol, int sv[2])
  318. {
  319.   char name[FIFO_NAMELEN];
  320.   struct fileinfo *f0;
  321.  
  322.   chkabort();
  323.   if (!_fifo_ok)
  324.     {
  325.       errno = ENXIO;
  326.       return -1;
  327.     }
  328.  
  329.   _sprintf(name, "uxfifo.%lx", _fifo_base + _fifo_offset++);
  330.  
  331.   if ((sv[0] = alloc_fifo(name, TRUE, TRUE, TRUE)) >= 0)
  332.     if ((sv[1] = alloc_fifo(name, TRUE, TRUE, FALSE)) >= 0) return 0;
  333.     else
  334.       {
  335.     if (f0 = _find_fd(sv[0])) free_fifo(f0->userinfo);
  336.     _free_fd(sv[0]);
  337.       }
  338.   return -1;
  339. }
  340.